home *** CD-ROM | disk | FTP | other *** search
- /*
- Sound.c
-
- Simple plug-in source to play sounds (2-channels) asynchronously. OK, so it won't do for a highly polished game
- which needs four-channel double-buffering, but it suffices for most stuff.
-
- By Ross Younger, ©1996. You are free to use any or all of this source code in your own projects. Just don't ask me
- to support it.
-
- Caveat: Of course, async sounds don't by default report back when they are finished. You might want to modify the
- callback procs if you feel so inclined. Good luck!
-
-
- ** DO NOT ADD THIS FILE DIRECTLY TO YOUR PROJECT **
- Copy it, and add the copy, because you need to alter the constants.
- */
-
- #include <MixedMode.h>
- #include <Sound.h>
-
- #define kNumberSounds 3 // number of sounds to load
- #define kFirstSoundID 1000 // ID of first sound
-
- /*
- Change the constants to match your resources. The sounds are assumed to be sequential, starting with kFirstSoundID.
-
- Call InitSound() during your init routine. This will load in all the sounds, taking up space in your heap zone.
- Call KillSound() during your cleanup.
-
- To play a sound, use PlayASound(soundNumber, priority);
- where soundNumber is the number within the file (starting at 0); eg. with sounds ID 100 thru 105,
- soundNumber 4 would give 'snd ' ID 103.
-
- PlayASound handles priorities like this:
- if [ (channel1clear) or (newpriority >= sound1currentpriority) ], play sound on channel 1
- else if [ (channel2clear) or (newpriority >= sound1currentpriority) ], play sound on channel 2
- else ignore the sound request.
-
- Or, for those of us who speak English: a sound of a higher (or equal) priority will override one that is still playing.
- The PlayASound routine tries to find a free channel, or one whose priority is greater than or equal to the one already
- playing there.
-
- * Check out the InitSound; it has error traps that give off weird return values. *
-
- */
-
- // Constants
- #define kSoundDone 913
- #define kSoundDone2 749
-
- // Prototypes
- short InitSound (void);
- void KillSound (void);
- void PlayASound (short soundID, short priority);
-
- void PlaySound1 (short, short);
- void PlaySound2 (short, short);
- pascal void ExternalCallBack (SndChannelPtr, SndCommand);
- pascal void ExternalCallBack2 (SndChannelPtr, SndCommand);
- void LoadAllSounds (void);
- OSErr LoadBufferSounds (void);
- OSErr DumpBufferSounds (void);
- OSErr OpenSoundChannel (void);
- OSErr CloseSoundChannel (void);
-
- // Globals for this source file
- SndCallBackUPP externalCallBackUPP, externalCallBackUPP2;
- SndChannelPtr externalChannel, externalChannel2;
- Ptr theSoundData[kNumberSounds];
- short externalPriority, externalPriority2;
- Boolean channelOpen, soundOn;
-
- /**********************************************************************************/
- /*
- You *can* use PlaySound1 and PlaySound2 directly, but I wouldn't recommend it.
- */
- void PlaySound1 (short soundID, short priority)
- {
- SndCommand theCommand;
- OSErr theErr;
-
- theCommand.cmd = flushCmd;
- theCommand.param1 = 0;
- theCommand.param2 = 0L;
- theErr = SndDoImmediate(externalChannel, &theCommand);
-
- theCommand.cmd = quietCmd;
- theCommand.param1 = 0;
- theCommand.param2 = 0L;
- theErr = SndDoImmediate(externalChannel, &theCommand);
-
- externalPriority = priority;
-
- theCommand.cmd = bufferCmd;
- theCommand.param1 = 0;
- theCommand.param2 = (long)(theSoundData[soundID]);
- theErr = SndDoImmediate(externalChannel, &theCommand);
-
- theCommand.cmd = callBackCmd;
- theCommand.param1 = kSoundDone;
- theCommand.param2 = SetCurrentA5();
- theErr = SndDoCommand(externalChannel, &theCommand, true);
- }
- /**********************************************************************************/
- void PlaySound2 (short soundID, short priority)
- {
- SndCommand theCommand;
- OSErr theErr;
-
- theCommand.cmd = flushCmd;
- theCommand.param1 = 0;
- theCommand.param2 = 0L;
- theErr = SndDoImmediate(externalChannel2, &theCommand);
-
- theCommand.cmd = quietCmd;
- theCommand.param1 = 0;
- theCommand.param2 = 0L;
- theErr = SndDoImmediate(externalChannel2, &theCommand);
-
- externalPriority2 = priority;
-
- theCommand.cmd = bufferCmd;
- theCommand.param1 = 0;
- theCommand.param2 = (long)(theSoundData[soundID]);
- theErr = SndDoImmediate(externalChannel2, &theCommand);
-
- theCommand.cmd = callBackCmd;
- theCommand.param1 = kSoundDone2;
- theCommand.param2 = SetCurrentA5();
- theErr = SndDoCommand(externalChannel2, &theCommand, true);
- }
- /**********************************************************************************/
- void PlayASound (short soundID, short priority)
- // Remember! Pass as soundID the sound-number-in-file, NOT the ID!
- {
- if ((soundID >= 0) && (soundID < kNumberSounds)) // Ignore invalid IDs
- {
- if (soundOn)
- {
- if (externalPriority < externalPriority2)
- {
- if (priority >= externalPriority)
- PlaySound1(soundID, priority);
- }
- else
- {
- if (priority >= externalPriority2)
- PlaySound2(soundID, priority);
- }
- }
- }
- }
- /**********************************************************************************/
- // Don't worry about this macro! Just accept it!
-
- RoutineDescriptor ExternalCallBackRD =
- BUILD_ROUTINE_DESCRIPTOR(uppFilePlayCompletionProcInfo, ExternalCallBack);
-
- pascal void ExternalCallBack (SndChannelPtr theChannel, SndCommand theCommand)
- {
- long thisA5, wasA5;
-
- if (theCommand.param1 == kSoundDone)
- {
- wasA5 = theCommand.param2;
- thisA5 = SetA5(wasA5);
-
- externalPriority = 0;
-
- thisA5 = SetA5(thisA5);
- }
- }
- /**********************************************************************************/
- RoutineDescriptor ExternalCallBackRD2 =
- BUILD_ROUTINE_DESCRIPTOR(uppFilePlayCompletionProcInfo, ExternalCallBack2);
-
- pascal void ExternalCallBack2 (SndChannelPtr theChannel, SndCommand theCommand)
- {
- long thisA5, wasA5;
-
- if (theCommand.param1 == kSoundDone2)
- {
- wasA5 = theCommand.param2;
- thisA5 = SetA5(wasA5);
-
- externalPriority2 = 0;
-
- thisA5 = SetA5(thisA5);
- }
- }
- /**********************************************************************************/
- OSErr LoadBufferSounds (void)
- {
- Handle theSound;
- long soundDataSize;
- OSErr theErr;
- short i;
-
- theErr = noErr;
-
- for (i = 0; i < kNumberSounds; i++)
- {
- theSound = GetResource('snd ', i + kFirstSoundID);
- if (theSound == 0L)
- return (ResError());
-
- HLock(theSound);
- soundDataSize = GetHandleSize(theSound) - 20L;
- HUnlock(theSound);
-
- theSoundData[i] = NewPtr(soundDataSize);
- if (theSoundData[i] == 0L)
- return (ResError());
- HLock(theSound);
- BlockMove((Ptr)(*theSound + 20L), theSoundData[i], soundDataSize);
- HUnlock(theSound);
- ReleaseResource(theSound);
- }
-
- return (theErr);
- }
- /**********************************************************************************/
- OSErr DumpBufferSounds (void)
- {
- OSErr theErr;
- short i;
-
- theErr = noErr;
-
- for (i = 0; i < kNumberSounds; i++)
- {
- if (theSoundData[i] != 0L)
- DisposPtr(theSoundData[i]);
- theSoundData[i] = 0L;
- }
-
- return (theErr);
- }
- /**********************************************************************************/
- OSErr OpenSoundChannel (void)
- {
- OSErr theErr;
-
- #if USESROUTINEDESCRIPTORS
- externalCallBackUPP = &ExternalCallBackRD;
- externalCallBackUPP2 = &ExternalCallBackRD2;
- #else
- externalCallBackUPP = (SndCallBackUPP) &ExternalCallBack;
- externalCallBackUPP2 = (SndCallBackUPP) &ExternalCallBack2;
- #endif
-
- theErr = noErr;
-
- if (channelOpen)
- return (theErr);
-
- externalChannel = 0L;
- theErr = SndNewChannel(&externalChannel,
- sampledSynth, initNoInterp + initMono,
- (SndCallBackUPP)externalCallBackUPP);
- if (theErr == noErr)
- channelOpen = true;
-
- externalChannel2 = 0L;
- theErr = SndNewChannel(&externalChannel2,
- sampledSynth, initNoInterp + initMono,
- (SndCallBackUPP)externalCallBackUPP2);
- if (theErr == noErr)
- channelOpen = true;
-
- return (theErr);
- }
- /**********************************************************************************/
- OSErr CloseSoundChannel (void)
-
- {
- OSErr theErr;
-
- theErr = noErr;
-
- if (!channelOpen)
- return (theErr);
-
- if (externalChannel != 0L)
- theErr = SndDisposeChannel(externalChannel, true);
- externalChannel = 0L;
-
- if (externalChannel2 != 0L)
- theErr = SndDisposeChannel(externalChannel2, true);
- externalChannel2 = 0L;
-
- if (theErr == noErr)
- channelOpen = false;
-
- return (theErr);
- }
- /**********************************************************************************/
- short InitSound (void)
- /*
- This function loads the sounds and opens the channels. Return value is 0 for success, -1 for couldn't load the sounds,
- and -2 for couldn't open the channels.
- */
- {
- OSErr theErr;
-
- soundOn = true;
-
- externalChannel = 0L;
- externalChannel2 = 0L;
- externalPriority = 0;
- externalPriority2 = 0;
-
- theErr = LoadBufferSounds();
- if (theErr != noErr) // Failed to load the sounds (missing resource?). You might want to change how this is handled.
- return (-1);
-
- theErr = OpenSoundChannel();
- if (theErr != noErr) // Couldn't open the sound channels (already in use?). Again, you may want to change how this is handled.
- return (-2);
- return (0); // 0 for success!
- }
- /**********************************************************************************/
- void KillSound (void)
- {
- OSErr theErr;
-
- theErr = DumpBufferSounds();
- theErr = CloseSoundChannel();
- } // Errors are ignored as we're closing down anyway.
- /**********************************************************************************/
- // The end.